/* 
 * File:   wikiList.h
 * Author: simpatico
 *
 * Created on June 4, 2010, 4:40 PM
 */

#ifndef FUNCTLIST_H
#define	FUNCTLIST_H

#include <stdio.h>    /* for printf */
#include <stdlib.h>   /* for malloc */
//#include <string>
#include <assert.h>

//using namespace std;

typedef struct node {
    const int* data;
    struct node* next;
} list;

typedef struct function {
    const char* name;
    const char* type;
    const list* args;
    const list* body;
} funct;

union value {
    char * s;
    char c;
    float f;
    double d;
    int i;
    bool b;
};

typedef struct variable {
    char* type;
    const char* name;
    const char* typeQualifier;
    bool returned;
    union value value;
} var;


const char * dQualifier = NULL; //not "const";

const list *list_add(const list *p, const list* f) {
    //f->next = NULL; necessary to comment
	if(f){
		list * tmp = (list *)f;
		while (tmp->next)
		    tmp = tmp->next;

		//assert(!tmp->next);
		tmp->next = (list *)p;
    }
	else{
		return p;
	}
    return f;
}

void list_remove(const list **p) {
    if (p != NULL && *p != NULL) {
        list *n = (list*)*p;
        *p = (*p)->next;
        free(n);
    }
}

list **list_search(list **n, const int* data) {
    if (n == NULL)
        return NULL;

    while (*n != NULL) {
        if ((*n)->data == data) {
            return n;
        }
        n = &(*n)->next;
    }
    return NULL;
}

bool findNode(const list *p, const char* fName, const bool varr) {
    assert(fName);
    while (p) {
        if (varr) {
            var *data = (var*) p->data;
            if (data && data->name && (strncmp(data->name, fName, 100) == 0)) return true;
        } else {
            funct *data = (funct*) p->data;
            if (data != NULL && data->name && (strncmp(data->name, fName, 100) == 0)) return true;
        }
        p = p->next;
    }
    return false;
}

var* checkVar(const list *p, const char* fName) {
    while (p != NULL) {
		var *data = (var*) p->data;
		if (data && data->name && (strncmp(data->name, fName, 100) == 0)) return data;
        p = p->next;
    }
    return NULL;
}

var* newVar(const char * type, const char* name, const char* qualifier, const union value val){
    var *v = (var*)malloc(sizeof (var));
    assert(v);
    v->name = name;
    v->type = (char*) type;
    v->typeQualifier = qualifier;
    v->value = val;
    v->returned = false;

    return v;
}

var* newVarInt(const char* name, int val){
    const char * type = "int";
    union value u;
    u.i = val;
    var * v = newVar(type, name, dQualifier, u);
    return v;
}

var* newVarFloat(const char* name, float val){
    const char * type = "float";
    union value u;
    u.f = val;
    var * v = newVar(type, name, dQualifier, u);
    return v;
}

var* newVarString(const char* name, const char * val){
    const char * type = "string";
    union value u;
    u.s = (char *)val;
    var * v = newVar(type, name, dQualifier, u);
    return v;
}

var* newVarChar(const char* name, char val){
    const char * type = "char";
    union value u;
    u.c = val;
    var * v = newVar(type, name, dQualifier, u);
    return v;
}

var* newVarBool(const char* name, bool val){
    const char* type = "bool";
    union value u;
    u.b = val;
    var* v = newVar(type, name, dQualifier, u);
    return v;
}

var* newVarWithoutValue(const char* type, const char* name, const char* qualifier){
    union value a;
    var *v = newVar(type, name, qualifier, a);
    //default initialization

    if(type){
        if (strncmp(type, "int", 4) == 0) {
       	    v->value.i = 0;
        } else if (strncmp(type, "float", 6) == 0) {
   	        v->value.f = 0.0;
        } else if (strncmp(type, "char", 5) == 0) {
   	        v->value.c = '\0';
        } else if (strncmp(type, "string", 7) == 0) {
        	v->value.s = (char*)"";
        }
    }
    return v;
}

funct* newFunct(const char* type, const list* args, const char* name, const list* body) {
    funct *f = (funct*) malloc(sizeof (funct));
    assert(f);
    f->name = name;
    f->args = args;
    f->type = type;
    f->body = body;
    return f;
}

list* newN(const int* v) {
    list* node = (list*)malloc(sizeof (list));
    assert(node);
    node->data = v;
    node->next = NULL;
    return node;
}

/**
 *
 * @param type
 * @param args: may be null for functions too.
 * @param name
 * @param qualifier
 * @param body
 * @return
 */
list* newNode(const char *type, const list* args, const char* name, const char* qualifier, const bool varr, const list* body) {
    if (varr) {
        var* v = newVarWithoutValue(type, name, qualifier);
        return newN((const int*) v);
    } else {
        funct* f = newFunct(type, args, name, body);
        return newN((const int*) f);
    }
}


#endif

